/*
 *  heap.cpp
 *  joosVM
 *
 *  Created by Smári Waage on 11.6.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#include "heap.h"
#include <stdio.h>
#include <cstring>

int heapsize = kHeapInitSize;

//Note real pointers..
static Heap* H;
static Heap* HP;

//if contracts are enabled then during gc extra checks are made.
#if CONTRACTS
static Heap* gcH, *gcHP;
static bool doinggc = false;
#endif

//not realPointer
//static Stack* S;
static MethodArea* M;

ThreadContext Heap::threads[10];

Heap* Heap::BuildHeap(){
	HP = H = (Heap*)calloc(kHeapInitSize,1);
	return HP;
}

void Heap::TearDown(){
	delete H;
}

MethodArea* Heap::getMethodArea(){
	return M;
}

void Heap::setMethodArea(MethodArea* methodArea){
	M = methodArea;
}

void* Heap::allocObject(unsigned int size) {
	REQUIRE(size % 4 == 0)
	
	// TODO: if (!IsInitialized()) signal error
		
	// Allocate object
	void* object = HP;
	
	dout(debug_heap,"hp %p\n",HP);
	
	// Advance the heap pointer, passed the size of the newly created object.
	HP += size;
	
	//printf("size left %p %p %i \n",HP, H, (HP-H));
	ENSURE((HP - H) < heapsize)  
	return object;
}

int Heap::getHeapSize(){
	return heapsize;
}
 

#if CONTRACTS 
//to validate pointer addresses, for the contracts.
bool Heap::isAddressOk(void* addr){
	//return (!doinggc) || (addr>=H && addr<=HP);
	if(doinggc)
		return true;
	else
		if(addr>=H && addr<=HP)
			return true;
		else{
			printf(" failing address %p bouderies %p %p\n",addr,H,HP);
			return false;
		}
}
void Heap::printHandHP(){
	printf("%p %p",H,HP);
}
bool Heap::isGCAddressOk(void* addr){
	return doinggc && addr>=gcH && addr<=gcHP ;
}
#endif


bool Heap::shouldWedoGC(){
	//Todo: nicer!!
	return heapsize - (HP - H) < 10000  ;//(size + HP - H) >= heapsize;
}

//begin gc
void* Heap::startGC(){
	//Todo:some expansion strategi
	if(heapsize<kHeapMaxSize)
		heapsize = heapsize *2;
	
	Heap* newH = (Heap*)calloc(heapsize,1);
	
//just a help to the contracts to identify if an address is valid during gc
#if CONTRACTS
	doinggc = true;
	gcH = newH;
	gcHP = newH +heapsize;
#endif
	
	return newH;
}

//end the gc, clear up and clean the old space.
//we could of course hold on the space until we use 
//it again, but we choose to use extra time on allocation 
// also a forgotten pointer will fail in invocation attemt.
void Heap::endGC(Heap* newH, Heap* newHP){
	free(H);
	//realloc(newH, "something less"); //give something back at some point. 
	H = newH;
	HP = newHP;
	
#if CONTRACTS
	doinggc = false;
#endif
}



